package com.yingwei.mining.appletversion;

/*
 * @(#)Graph.java	1.9 99/08/04
 *
 * Copyright (c) 1997, 1998 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
 * modify and redistribute this software in source and binary code form,
 * provided that i) this copyright notice and license appear on all copies of
 * the software; and ii) Licensee does not utilize the software in a manner
 * which is disparaging to Sun.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
 * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
 * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
 * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
 * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
 * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
 * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
 * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 *
 * This software is not designed or intended for use in on-line control of
 * aircraft, air traffic, aircraft navigation or aircraft communications; or in
 * the design, construction, operation or maintenance of any nuclear
 * facility. Licensee represents and warrants that it will not use or
 * redistribute the Software for such purposes.
 */

import java.util.*;
import java.util.List;
import java.awt.*;
import java.applet.Applet;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

import javax.imageio.ImageIO;

import com.yingwei.mining.appletversion.Excavator;
import com.yingwei.mining.appletversion.Position;
import com.yingwei.mining.appletversion.UnloadArea;

public class GraphApplet extends Applet implements ActionListener, ItemListener
{
    GraphPanel graphPanel;
    Panel controlPanel;
    String backgroundImageFile;
    
    Button save = new Button("Save");
    Button load = new Button("Load");
    Button addConnection = new Button("Add Connection");
    Button addUnloadArea = new Button("Add UnloadArea");
    Button addExcavator = new Button("Add Excavator");
    Button switchView = new Button("Switch View");
    Checkbox showLength = new Checkbox("Show Length");
    Checkbox showIcon = new Checkbox("Show Icon");

    void load()
    {
	BufferedImage truckImg = null;
	BufferedImage excavatorImg = null;
	BufferedImage unloadAreaImg = null;
	BufferedImage backgroundImg = null;
	try
	{
	    truckImg = ImageIO.read(new File(
		    "C:\\workspace\\carmining\\image\\truck.jpg"));
	    excavatorImg = ImageIO.read(new File(
		    "C:\\workspace\\carmining\\image\\excavator.jpg"));
	    unloadAreaImg = ImageIO.read(new File(
		    "C:\\workspace\\carmining\\image\\unloadarea.jpg"));
	    File loadFile = new File(
		    "c:\\workspace\\carmining\\config\\config.txt");
	    BufferedReader bfr = new BufferedReader(new FileReader(loadFile));
	    backgroundImageFile = bfr.readLine();
	    backgroundImg = ImageIO.read(new File(backgroundImageFile));
	    graphPanel.setBackgroundImage(backgroundImg);

	    String line1 = bfr.readLine();
	    for (StringTokenizer t = new StringTokenizer(line1, ","); t
		    .hasMoreTokens();)
	    {
		String str = t.nextToken();
		int i = str.indexOf('-');
		if (i > 0)
		{
		    int len = 0;
		    graphPanel.addEdge(str.substring(0, i), str
			    .substring(i + 1), len);
		}
	    }
	    String line2 = bfr.readLine();
	    int numberOfNodesToLoad = Integer.parseInt(line2);
	    for (int i = 0; i < numberOfNodesToLoad; i++)
	    {
		Node n = graphPanel.nodes[i];
		String str = bfr.readLine();
		String[] nameXY = str.split("--");
		// n.lbl = nameXY[0];
		n.x = Double.parseDouble(nameXY[1]);
		n.y = Double.parseDouble(nameXY[2]);
		double strength = Double.parseDouble(nameXY[3]);
		if (n.lbl.charAt(0) == 'u')
		{
		    n.device = new UnloadArea(
			    new Position((int) n.x, (int) n.y), unloadAreaImg);
		    n.device.setId( n.lbl );
		    n.device.setStrength(strength);
		}
		if (n.lbl.charAt(0) == 'c')
		{
		    // n.device = new UnloadArea(new
		    // Position((int)n.x,(int)n.y), unloadAreaImg );
		}
		if (n.lbl.charAt(0) == 'e')
		{
		    n.device = new Excavator(
			    new Position((int) n.x, (int) n.y), excavatorImg);
		    n.device.setId( n.lbl );
		    n.device.setStrength(strength);
		}
		
	    }
	    bfr.close();
	}
	catch (IOException e)
	{
	    e.printStackTrace();
	}

	// update length calculation of edges
	graphPanel.updateEdgeLen();

	// add routes
	for (int i = 0; i < graphPanel.nnodes; i++)
	{
	    if( graphPanel.nodes[i].lbl.charAt(0) == 'e' )
	    {
		for (int j = 0; j < graphPanel.nnodes; j++)
		{
		    if( graphPanel.nodes[j].lbl.charAt(0) == 'u' )
		    {
			String route = findShortestRoute(i,j);
			String[] splits = route.split(",:");
			String[] edges = splits[0].split(",");
			double len = Double.parseDouble(splits[1]);	
			graphPanel.addRoute(edges, len);
		    }
		}
	    }
	}
	
	// add trucks
	graphPanel.ntrucks = 40;
	for (int i = 0; i < graphPanel.ntrucks; i++)
	{
	    Instruction inst = new Instruction("init", graphPanel.routes[0]);
	    Truck t = new Truck(truckImg,inst);
	    t.setInstruction(inst);
	    double x = graphPanel.nodes[inst.getRoute().edges[0].from].x;
	    double y = graphPanel.nodes[inst.getRoute().edges[0].from].y;
	    t.setPosition(new Position((int)x,(int)y));
	    t.setGraphPanel(graphPanel);
	    graphPanel.trucks[i] = t;
	}
    }

    void save()
    {
	try
	{
	    File saveFile = new File(
		    "c:\\workspace\\mining\\config\\config.txt");
	    BufferedWriter bwr = new BufferedWriter(new FileWriter(saveFile));
	    bwr.write(backgroundImageFile + "\n");
	    for (int i = 0; i < graphPanel.nedges; i++)
	    {
		Edge e = graphPanel.edges[i];
		bwr.write(graphPanel.nodes[e.from].lbl + "-"
			+ graphPanel.nodes[e.to].lbl + ",");
	    }
	    bwr.write("\n");
	    bwr.write(graphPanel.nnodes + "\n");
	    for (int i = 0; i < graphPanel.nnodes; i++)
	    {
		Node n = graphPanel.nodes[i];
		double strength = 0.0;
		if( n.device != null )
		{
		    strength = n.device.getStrength();
		}
		bwr.write(n.lbl + "--" + n.x + "--" + n.y + "--" + strength + "\n");
	    }
	    bwr.close();
	}
	catch (IOException e)
	{
	    e.printStackTrace();
	}
    }

    String findShortestRoute(int from, int to)
    {
	// dijkstra algorithm
	LinkedList<Integer> queue = new LinkedList<Integer>();
	boolean[] visited = new boolean[graphPanel.nnodes];
	double[] values = new double[graphPanel.nnodes];
	String[] routes = new String[graphPanel.nnodes];

	// init the data structure
        for (int i = 0; i < graphPanel.nnodes; i++)
        {
            visited[i] = false;	
            values[i] = Double.MAX_VALUE;
            routes[i] = "";
        }
        queue.add( from );
        values[from] = 0;
        routes[from] = from + ",";
        while( hasUnvisitedNode(visited) && queue.size()>0)
        {
            Integer pop = queue.removeFirst();
            visited[pop]=true;
            Integer[] next = getNeighbors( pop );
            for( int ii : next )
            {
        	if( !visited[ii] )
        	{
        	    queue.add( ii );
        	    double len = lengthBetweenNodes( ii, pop );
        	    if( values[pop] + len < values[ii] )
        	    {
        		values[ii] = values[pop] + len;
        		routes[ii] = routes[pop] + ii + ",";
        	    }
        	}
            }
        }
        return routes[to] + ":" + values[to];
    }

    Integer[] getNeighbors(int i)
    {
	List<Integer> result = new ArrayList<Integer>();
	for (int j = 0; j < graphPanel.nedges; j++)
	{
	    if (graphPanel.edges[j].from == i)
	    {
		result.add(graphPanel.edges[j].to);
	    }
	    if (graphPanel.edges[j].to == i)
	    {
		result.add(graphPanel.edges[j].from);
	    }
	}
	return (Integer[]) result.toArray(new Integer[0]);
    }

    boolean hasUnvisitedNode(boolean[] visited)
    {
	for (boolean b : visited)
	{
	    if (!b)
		return true;
	}
	return false;
    }

    double lengthBetweenNodes(int from, int to)
    {
	for (int j = 0; j < graphPanel.nedges; j++)
	{
	    if ((graphPanel.edges[j].from == from && graphPanel.edges[j].to == to)
		    || (graphPanel.edges[j].from == to && graphPanel.edges[j].to == from))
	    {
		return graphPanel.edges[j].len;
	    }
	}
	return Double.MAX_VALUE;
    }

    public void init()
    {
	setLayout(new BorderLayout());

	graphPanel = new GraphPanel(this);
	add("Center", graphPanel);
	controlPanel = new Panel();
	add("South", controlPanel);

	controlPanel.add(save);
	save.addActionListener(this);
	controlPanel.add(load);
	load.addActionListener(this);
	controlPanel.add(addConnection);
	addConnection.addActionListener(this);
	controlPanel.add(addUnloadArea);
	addUnloadArea.addActionListener(this);
	controlPanel.add(addExcavator);
	addExcavator.addActionListener(this);
	controlPanel.add(switchView);
	switchView.addActionListener(this);

	controlPanel.add(showLength);
	showLength.addItemListener(this);
	controlPanel.add(showIcon);
	showIcon.addItemListener(this);

	load();
    }

    public void destroy()
    {
	remove(graphPanel);
	remove(controlPanel);
    }

    public void start()
    {
	graphPanel.start();
    }

    public void stop()
    {
	graphPanel.stop();
    }

    public void actionPerformed(ActionEvent e)
    {
	Object src = e.getSource();

	if (src == save)
	{
	    play(getCodeBase(), "audio/computer.au");
	    save();
	}

	if (src == load)
	{
	    play(getCodeBase(), "audio/gong.au");
	    load();
	}

	if (src == addConnection)
	{
	    graphPanel.addEdge("c" + System.currentTimeMillis(), "e1", 50);
	    System.out.println("Add edge");
	}

	if (src == addExcavator)
	{
	    graphPanel.addEdge("e" + System.currentTimeMillis(), "e1", 50);
	}

	if (src == addUnloadArea)
	{
	    graphPanel.addEdge("u" + System.currentTimeMillis(), "e1", 50);
	}

	if (src == switchView)
	{
	    if( graphPanel.viewMode++ > 2 )
		graphPanel.viewMode = 0;
	}
    }

    public void itemStateChanged(ItemEvent e)
    {
	Object src = e.getSource();
	boolean on = e.getStateChange() == ItemEvent.SELECTED;
	if (src == showLength)
	    graphPanel.showLength = on;
	else if (src == showIcon)
	    graphPanel.showIcon = on;
    }

    public String getAppletInfo()
    {
	return "Title: GraphLayout \nAuthor: Yingwei";
    }

}